/*
 * Copyright (c) 2010, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ALKES_TBIT_ARRAY_H_INCLUDED_
#define ALKES_TBIT_ARRAY_H_INCLUDED_

#include "alkes/core/Macro.h"

namespace alkes {


template<typename T>
class TBitArray
{
public:
    enum
    {
        AL_MAX_BITS = sizeof(T) * 8,
    };

    TBitArray(T initial = 0);

    bool operator [](uint32_t idx) const;
    void setFlag(uint32_t idx, bool is_on = true);
    void clearFlag(uint32_t idx);

private:
    T bits_;
};

template<typename T>
TBitArray<T>::TBitArray(T initial)
: bits_(initial)
{
}

template<typename T>
bool TBitArray<T>::operator [](uint32_t idx) const
{
    return AL_BITS_IS_ON(bits_, (T)1 << idx);
}

template<typename T>
void TBitArray<T>::setFlag(uint32_t idx, bool is_on)
{
    if (is_on)
    {
        AL_BITS_ON(bits_, (T)1 << idx);
    }
    else
    {
        clearFlag(idx);
    }
}

template<typename T>
void TBitArray<T>::clearFlag(uint32_t idx)
{
    AL_BITS_OFF(bits_, (T)1 << idx);
}


template<typename T, int N>
class TBitArrays
{
public:
    enum
    {
        AL_MAX_BITS     = sizeof(T) * 8 * N,
        AL_BIT_MASK     = sizeof(T) * 8 - 1,
        AL_BIT_SHIFT    = sizeof(T) + 2,
    };

    TBitArrays();

    bool operator [](uint32_t idx) const;
    void setFlag(uint32_t idx, bool is_on = true);
    void clearFlag(uint32_t idx);

private:
    T bits_[N];
};

template<typename T, int N>
TBitArrays<T, N>::TBitArrays()
{
    memset(bits_, 0, sizeof(bits_));
}

template<typename T, int N>
bool TBitArrays<T, N>::operator [](uint32_t idx) const
{
    return AL_BITS_IS_ON(bits_[idx>>AL_BIT_SHIFT], (T)1 << (idx&AL_BIT_MASK));
}

template<typename T, int N>
void TBitArrays<T, N>::setFlag(uint32_t idx, bool is_on)
{
    if (is_on)
    {
        AL_BITS_ON(bits_[idx>>AL_BIT_SHIFT], (T)1 << (idx&AL_BIT_MASK));
    }
    else
    {
        clearFlag(idx);
    }
}

template<typename T, int N>
void TBitArrays<T, N>::clearFlag(uint32_t idx)
{
    AL_BITS_OFF(bits_[idx>>AL_BIT_SHIFT], (T)1 << (idx&AL_BIT_MASK));
}

template<class T> struct BitCount;
template<> struct BitCount<uint8_t> { enum { BIT_COUNT = 8}; };
template<> struct BitCount<uint16_t> { enum { BIT_COUNT = 16}; };
template<> struct BitCount<uint32_t> { enum { BIT_COUNT = 32}; };

template<class T, int M>
struct EnoughSize
{
    enum
    {
        count = (M + (BitCount<T>::BIT_COUNT-1)) / BitCount<T>::BIT_COUNT,
    };
};

}

#endif
